The Pushable Tile Entities data pack allows vanilla Java users to push and pull tile entities like chests, dispensers, hoppers, and the like using special pistons. These "pistons" are crafted by dropping an actual piston and a chest on top of a crafting table. They will combine and form into a special item that will allow you to place these special chest pushers.

Inside each function file, I have commented technical descriptions of what the commands inside do. This document will explain how this data pack works overall, in more laymans terms. 

You may notice that I do not use actual pistons or sticky pistons to push or pull the tile entities. Instead I use droppers and dispensers. The reason for this is that pistons do not update their block state if they cannot extend. Since you can't push chests with regular pistons in Java, that piston will not extend, which means it will not update its block state. Trying to detect if a piston is powered if it has an unpushable block in front of it is not worth the effort. Droppers and dispensers work perfectly as a placeholder for pistons and sticky pistons. Much like pistons, they have six directions, but they can also be powered regardless of their surrounding blocks.

When you craft the special pistons, you will be granted a bat spawn egg that looks like the head of a piston, albeit dark. The darkness is due to how bat spawn eggs are textured, and I don't know how to change that to make it look normal. The bat spawn egg has special data that when summoned, will replace the bat with a dropper or dispenser, and summon an area effect cloud marker at that location, thereby turning them into a "piston".

The area effect cloud inside the "pistons" is crucial to their pushing and pulling logic. Once you power the pistons, it will start counting all the blocks it can push, and try to push them. Counting blocks next to other slime blocks was the biggest challenge of this entire data pack. So much so, in fact, that this is actually it's third rewrite, as I try new ideas on how to count slime blocks and what blocks are attached to them. The current system might work, but that does not mean there couldn't be a more optimized solution.

How does counting blocks in front of a piston work?

When the piston gets powered, it checks for a valid block in front of it. Valid blocks are blocks that are not in the #pushable_chests:passable or #pushable_chests:immovable block tags. At the valid block, a piston attach marker area effect cloud is summoned. Piston attach markers in slime blocks get tagged differently than those in other valid blocks. If the attach marker is a non-slime block, it will only check for other valid blocks that are in front of themselves, and not already occupied by an attach marker. If the attach marker is a slime block, however, it will check for other valid blocks in all directions of itself. At each location it finds another valid block, another attach marker is summoned, repeating the whole process until each block that the piston can push is either counted for, or the push limit is exceeded, or an immovable block is met.

Checking for valid surrounding blocks for each attach marker is not very efficent, and causes unnecessary lag as the number of checks grows exponentially for each added block. To combat this, only the newest attach markers check for valid surrounding blocks. Each new attach marker is also summoned with a special "current_" tag, which is then replaced with a "current" tag, and the "current" tags of older attach markers are removed. This greatly reduces the amount of redundancies as only the newest attach markers count their surrounding blocks.

Once all blocks are counted, and the piston isn't deemed immovable, it will then push its blocks. Pushing works by moving the block of each attach marker forward via the clone command. To make sure that all blocks are moved properly, we have to start the cloning process at the attach marker that is furthest away from the piston. This ensures that when cloning occurs, it does not override any other cloned blocks. Once the blocks are moved, the piston attach markers are killed.

Pulling blocks works the same way. Instead of moving forwards, it moves backwards, and the cloning starts at the attach marker furthest behind the piston. Valid non-slime blocks check for other valid blocks behind them instead of in front of them. 

Pushing and pulling entities works by tagging them if they're in the way of an attach marker, and then teleporting those tagged entities one block forward or backwards respectively.

With all that being said, there are probably some bugs. So use this datapack at your own discretion. If you do find bugs, DM me on discord (auxhil#0565) or reddit u/Auxhiliamith; or on the github page of this datapack.